/*
    @class: ThinkGearStreamParser
    @description: This class was developed using the code freely available at
www.neurosky.com. It is an adpatation from the C files: ThinkGearStreamparser.h and
ThinkGearStreamParser.c into a Qt C++ class.

    @author: Mirko Perkusich
             Taciana Rached
*/
/*
Copyright (c) 2010 Embedded Systems and Pervasive Laboratory, Federal
University of Campina Grande, Brazil, Angelo Perkusich, Mirko Perkusich,
Taciana Rached

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN  THE SOFTWARE.
*/
/*
 * @(#)ThinkGearStreamParser.h    2.0    Mar 04, 2008
 *
 * Copyright (c) 2008 NeuroSky, Inc. All Rights Reserved
 * NEUROSKY PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/* Ensure this header is only included once */
#ifndef THINKGEAR_STREAM_PARSER_H_
#define THINKGEAR_STREAM_PARSER_H_

/**
 * @file ThinkGearStreamParser.h
 *
 * The ThinkGear Stream Parser is used to parse bytes of ThinkGear
 * data streamed from any source.  Each arriving byte is fed into
 * the Parser using the THINKGEAR_parseByte() function, and a user
 * supplied callback function is called whenever DataRows are decoded
 * from complete ThinkGear Packets.  Each Parser can be initialized
 * to recognize either: streams of ThinkGear Packets, or streams
 * of 2-byte raw values (the old 5V ThinkGear stream format).
 *
 * @author Kelvin Soo
 * @version 2.0 Mar 04, 2008 Kelvin Soo
 *   - Renamed to ThinkGearStreamParser from ThinkGearStreamDecoder.
 *   - Revised to call a callback function instead of stuffing arriving
 *     data values into a ThinkGearData object.
 *   - Renamed symbols according to updated Packet vocabulary.
 * @version 1.0 Nov 27, 2007 Kelvin Soo
 *   - Initial version (ThinkGearStreamDecoder).
 */

/* Include all external libraries required by this header */
#include <stdlib.h>
#include <QObject>
#include <QDebug>

/* Parser types */
#define PARSER_TYPE_NULL       0x00
#define PARSER_TYPE_PACKETS    0x01    /* Stream bytes as ThinkGear Packets */
#define PARSER_TYPE_2BYTERAW   0x02    /* Stream bytes as 2-byte raw data */

/* Data CODE definitions */
#define PARSER_CODE_BATTERY            0x01
#define PARSER_CODE_POOR_QUALITY       0x02
#define PARSER_CODE_ATTENTION          0x04
#define PARSER_CODE_MEDITATION         0x05
#define PARSER_CODE_8BITRAW_SIGNAL     0x06
#define PARSER_CODE_RAW_MARKER         0x07

#define PARSER_CODE_RAW_SIGNAL         0x80
#define PARSER_CODE_EEG_POWERS         0x81
#define PARSER_CODE_ASIC_EEG_POWER_INT 0x83

/**
 * The Parser is a state machine that manages the parsing state.
 */
class ThinkGearStreamParser : public QObject
{
    Q_OBJECT;

public:
    /**
     * Constructor
     */
    explicit ThinkGearStreamParser();
    /**
     * Feeds the @c byte into the @c parser.  If the @c byte completes a
     * complete, valid parser, then the @c parser's handleDataValue()
     * function is automatically called on each DataRow in the Packet.
     * The return value provides an indication of the state of the
     * @c parser after parsing the byte.
     *
     * @param parser Pointer to an initialized ThinkGearDataParser object.
     * @param byte   The next byte of the data stream.
     *
     * @return -1 if @c parser is NULL.
     * @return -2 if a complete Packet was received, but the checksum failed.
     * @return -3 if an invalid Packet with PLENGTH > 170 was detected.
     * @return -4 if an invalid Packet with PLENGTH == 170 was detected.
     * @return -5 if the @c parser is somehow in an unrecognized state.
     * @return 0 if the @c byte did not yet complete a Packet.
     * @return 1 if a Packet was received and parsed successfully.
     *
     */
    int parseByte( unsigned char byte );

private:
    unsigned char   type;
    unsigned char   state;

    unsigned char   lastByte;

    unsigned char   payloadLength;
    unsigned char   payloadBytesReceived;
    unsigned char   payload[256];
    unsigned char   payloadSum;
    unsigned char   chksum;

    /**
     * Parses each row of data from the @c packet's Data[] block,
     * updating the fields of @c data as appropriate.
     */
    int parsePacketPayload();
    /**
     * Identifies if the data represents meditation level or attention level and
     * sens the corresponding signal.
     */
    void handleDataValue( unsigned char extendedCodeLevel,
                             unsigned char code, unsigned char numBytes,
                             const unsigned char *value);
signals:
    /** Sends the attention level */
    void attentionLevel(int aLevel);
    /** Sends the meditation level */
    void meditationLevel(int medLevel);
};

#endif /* THINKGEAR_STREAM_DECODER_H_ */

